/**
 * Created by Weizehua on 2017/1/26.
 */
import {Singleton} from "ts.di";
import {Handle, ParamType, Validators, Require, Sign, Verify} from "../Core/Dispatcher/Dispatcher";
import {Image} from "./Image";
import {RequestUserInfo} from "../Core/Dispatcher/Types";
import {Connection} from "typeorm";
import {Spot} from "./Spot";
import {MaxLen} from "../Core/Validator/Length";
import {isLogged} from "../User/UserHandler";
import {VerifyUpload} from "../Core/Dispatcher/Shortcut";
import {Album} from "../Album/Album";
import {DailyHeat, WeeklyHeat, MonthlyHeat, AlbumsHeats} from "../Album/AlbumsHeat";
import {User} from "../User/User";
import {FollowInfo} from "../FollowInfo/FollowInfo";

@Singleton()
export class ImageHandler {
    constructor(public typeorm: Connection) {
    }

    @Handle('/image/new')
    @ParamType({
        uploadInfo: {url: String,},
        spots: [{x: Number, y: Number, title: String, detail: String}],
        albumId: Number,
    })
    @Validators({
        spots: [{
            title: MaxLen(6),
            // detail: MaxLen(20),
        }]
    })
    @VerifyUpload()
    @Require(isLogged)
    async newImageHandler(userInfo: RequestUserInfo, param: any) {
        let url = param.uploadInfo.url;
        let spots: Spot[] = param.spots;

        let album: Album = <any>{id: param.albumId};

        let image = new Image();
        image.imageSource = url;
        image.user = <any>userInfo;
        image.album = album;

        await this.typeorm.entityManager.persist(image);
        for (let s of spots) {
            s.image = image;
        }
        await this.typeorm.getRepository(Spot).persist(spots);
        //noinspection JSIgnoredPromiseFromCall
        this.increaseAlbumHeats(album);
        return true;
    }

    private async increaseAlbumHeats(album: Album) {
        await this.increaseHeat(album, DailyHeat);
        await this.increaseHeat(album, WeeklyHeat);
        await this.increaseHeat(album, MonthlyHeat);
    }

    private async increaseHeat(album: Album, heatTable: AlbumsHeats) {
        let repository = await this.typeorm.getRepository(heatTable);
        repository.query(`UPDATE ${heatTable.name} SET heat = heat+1 WHERE album = ${Number(album.id)}`);
    }

    @Handle('/image/queryByAlbum/newer')
    @ParamType({
        albumId: Number,
        endId: Number
    })
    @Require(isLogged)
    @Sign('.images', [{id: true, user: true, album: true}])
    async queryNewerAlbumHandler(userInfo: RequestUserInfo, param: any) {
        let res = await this.typeorm.entityManager
            .createQueryBuilder(Image, 'image')
            .where('image.id > :id')
            .andWhere('image.album = :album')
            .setLimit(10)
            .leftJoinAndSelect('image.spots', 'spots')
            .setParameters({id: param.endId, album: param.albumId})
            .enableOption("RELATION_ID_VALUES")
            .getMany();

        return {
            success: true,
            images: res
        }
    }

    @Handle('/image/queryByAlbum/older')
    @ParamType({
        albumId: Number,
        startId: Number
    })
    @Sign('.images', [{id: true, user: true, album: true}])
    @Require(isLogged)
    async queryOlderAlbumHandler(userInfo: RequestUserInfo, param: any) {
        let res = await this.typeorm.entityManager
            .createQueryBuilder(Image, 'image')
            .where('image.id < :id')
            .andWhere('image.album = :album')
            .setLimit(10)
            .leftJoinAndSelect('image.spots', 'spots')
            .setParameters({id: param.startId, album: param.album})
            .enableOption("RELATION_ID_VALUES")
            .getMany();
        return {
            success: true,
            images: res
        }
    }

    @Handle('/image/queryByDynamic/newer')
    @ParamType({
        endId: Number
    })
    @Require(isLogged)
    @Sign('.images', [{id: true, user: true, album: true}])
    async queryNewerDynamicImageHandler(userInfo: RequestUserInfo, param: any) {
        let res = await this.typeorm.entityManager
            .createQueryBuilder(Image, 'image')
            .where('image.id > :id')
            .setLimit(10)
            .innerJoin(FollowInfo, 'f')
            .andWhere('f.follower = :user')
            .leftJoinAndSelect('image.spots', 'spots')
            .setParameters({id: param.endId, user: userInfo.id})
            .enableOption("RELATION_ID_VALUES")
            .getMany();

        return {
            success: true,
            images: res
        }
    }

    @Handle('/image/queryByDynamic/older')
    @ParamType({
        startId: Number
    })
    @Sign('.images', [{id: true, user: true, album: true}])
    @Require(isLogged)
    async queryOlderDynamicImageHandler(userInfo: RequestUserInfo, param: any) {
        let res = await this.typeorm.entityManager
            .createQueryBuilder(Image, 'image')
            .where('image.id < :id')
            .setLimit(10)
            .innerJoin(FollowInfo, 'f')
            .andWhere('f.follower = :user')
            .leftJoinAndSelect('image.spots', 'spots')
            .setParameters({id: param.startId, user: userInfo.id})
            .enableOption("RELATION_ID_VALUES")
            .getMany();
        return {
            success: true,
            images: res
        }
    }

    @Handle('/image/queryByUser/newer')
    @ParamType({
        userId: Number,
        endId: Number
    })
    @Require(isLogged)
    @Sign('.images', [{id: true, user: true, album: true}])
    async queryNewerImageHandler(userInfo: RequestUserInfo, param: any) {
        let res = await this.typeorm.entityManager
            .createQueryBuilder(Image, 'image')
            .where('image.id > :id')
            .andWhere('image.user = :user')
            .setLimit(10)
            .leftJoinAndSelect('image.spots', 'spots')
            .setParameters({id: param.endId, user: userInfo.id})
            .enableOption("RELATION_ID_VALUES")
            .getMany();

        return {
            success: true,
            images: res
        }
    }

    @Handle('/image/queryByUser/older')
    @ParamType({
        userId: Number,
        startId: Number
    })
    @Sign('.images', [{id: true, user: true, album: true}])
    @Require(isLogged)
    async queryOlderImageHandler(userInfo: RequestUserInfo, param: any) {
        let res = await this.typeorm.entityManager
            .createQueryBuilder(Image, 'image')
            .where('image.id < :id')
            .andWhere('image.user = :user')
            .setLimit(10)
            .leftJoinAndSelect('image.spots', 'spots')
            .setParameters({id: param.startId, user: param.userId})
            .enableOption("RELATION_ID_VALUES")
            .getMany();
        return {
            success: true,
            images: res
        }
    }

    @Handle('/image/spot/add')
    @ParamType({
        image: {id: Number, user: Number, album: Number},
        spot: {x: Number, y: Number, title: String, detail: String},
    })
    @Verify('image', {id: true, user: true, album: true})
    @Require(isLogged)
    async addSpotHandler(userInfo: RequestUserInfo, param: any) {
        let image = param.image;
        let spot = new Spot();
        spot.user = {id: userInfo.id} as User;
        spot.image = <Image>image;
        spot.x = param.spot.x;
        spot.y = param.spot.y;
        spot.title = param.spot.title;
        spot.detail = param.spot.detail;
        let res = await this.typeorm.entityManager
            .persist(spot);
        if (image.user !== userInfo.id) {
            //noinspection JSIgnoredPromiseFromCall
            this.increaseAlbumHeats(image.album);
        }
        return true;
    }
}


